package com.zzjx.datasource;

import com.redxun.common.utils.ExceptionUtil;
import io.seata.rm.datasource.DataSourceProxy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.util.Map;

@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {

    /**
     * 这个方法返回需要使用的dataSource的key值,然后根据这个key从
     * resolvedDataSources这个map里取出对应的DataSource,如果找不到
     * 就用默认的resolveDefaultDataSource
     *
     * @return java.lang.Object
     * @author zhaojiaxu
     * @date 2021/07/01 13:47
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }

    /**
     * 访问私有属性字段。
     *
     * @param instance
     * @param fieldName
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     */
    private static Object getValue(Object instance, String fieldName) throws IllegalAccessException, NoSuchFieldException {
        Field field = AbstractRoutingDataSource.class.getDeclaredField(fieldName);
        // 参数值为true，禁用访问控制检查
        field.setAccessible(true);
        return field.get(instance);
    }

    /**
     * 获取默认的数据源。
     *
     * @return
     */
    public DataSource getDefaultSource() {
        DataSource dataSource = null;
        try {
            dataSource = (DataSource) getValue(this, "resolvedDefaultDataSource");
        } catch (Exception ex) {
            log.error(ExceptionUtil.getExceptionMessage(ex));
        }
        return dataSource;
    }

    public Map<Object, Object> getDataSource() throws IllegalAccessException, NoSuchFieldException {

        Map<Object, Object> targetDataSources = (Map<Object, Object>) getValue(this, DataSourceUtil.TARGET_DATASOURCES);

        return targetDataSources;
    }

    /**
     * 获取当前数据库的类型。
     *
     * @return
     */
    public String getDbType() {
        DataSource dataSource = this.determineTargetDataSource();
        DataSourceProxy druidDataSource = (DataSourceProxy) dataSource;
        return druidDataSource.getDbType();
    }


    /**
     * 指定数据源是否存在。
     *
     * @param key
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchFieldException   boolean
     */
    public boolean isDataSourceExist(String key) throws IllegalAccessException, NoSuchFieldException {
        Map<Object, Object> targetDataSources = (Map<Object, Object>) getValue(this, DataSourceUtil.TARGET_DATASOURCES);
        return targetDataSources.containsKey(key);
    }

    /**
     * 根据别名删除数据源。
     *
     * @param key
     * @throws IllegalAccessException
     * @throws NoSuchFieldException   void
     */
    public void removeDataSource(String key) throws IllegalAccessException, NoSuchFieldException {
        Map<Object, Object> targetDataSources = (Map<Object, Object>) getValue(this, DataSourceUtil.TARGET_DATASOURCES);

        if (key.equals(DataSourceUtil.GLOBAL_DATASOURCE) || key.equals(DataSourceUtil.DEFAULT_DATASOURCE)) {
            throw new DataSourceException("datasource name :" + key + " can't be removed!");
        }
        targetDataSources.remove(key);
        setTargetDataSources(targetDataSources);
    }


    /**
     * 添加数据源。
     *
     * @param key
     * @param dataSource
     * @throws IllegalAccessException
     * @throws NoSuchFieldException   void
     */
    public void addDataSource(String key, Object dataSource) throws IllegalAccessException, NoSuchFieldException {
        Map<Object, Object> targetDataSources = (Map<Object, Object>) getValue(this, DataSourceUtil.TARGET_DATASOURCES);
        boolean rtn = isDataSourceExist(key);
        if (rtn) {
            throw new DataSourceException("datasource name :" + key + "is exists!");
        }
        targetDataSources.put(key, dataSource);
        setTargetDataSources(targetDataSources);
        afterPropertiesSet();
    }
}
